home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char sccsid[] = "@(#)inet.c 1.12 88/02/08 Copyr 1986 Sun Micro";
- #endif
-
- /*
- * Copyright (c) 1986 by Sun Microsystems, Inc.
- */
-
- /*
- * Standalone IP send and receive - specific to Ethernet
- * Includes ARP and Reverse ARP
- */
- #include "machparam.h"
- #include "boot.h"
- #include "saio.h"
- #include "socket.h"
- #include "if.h"
- #include "if_arp.h"
- #include "in.h"
- #include "if_ether.h"
- #include "in_systm.h"
- #include "ip.h"
- #include "sainet.h"
- #include "sunromvec.h"
- #include "idprom.h"
-
- #define millitime() (*romp->v_nmiclock)
-
- struct ether_addr etherbroadcastaddr = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- };
-
- struct arp_packet {
- struct ether_header arp_eh;
- struct ether_arp arp_ea;
- #define used_size (sizeof (struct ether_header)+sizeof(struct ether_arp))
- char filler[ETHERMIN - sizeof(struct ether_arp)];
- };
-
- #define WAITCNT 2 /* 4 seconds before bitching about arp/revarp */
-
- /*
- * Fetch our Ethernet address from the ID prom
- */
- myetheraddr(ea)
- struct ether_addr *ea;
- {
- struct idprom id;
-
- if (idprom(IDFORM_1, &id) != IDFORM_1) {
- printf("ERROR: missing or invalid ID prom\n");
- return;
- }
- *ea = *(struct ether_addr *)id.id_ether;
- }
-
- /*
- * Initialize IP state
- * Find out our Ethernet address and call Reverse ARP
- * to find out our Internet address
- * Set the ARP cache to the broadcast host
- */
- inet_init(sip, sain, tmpbuf)
- register struct saioreq *sip;
- register struct sainet *sain;
- char *tmpbuf;
- {
- myetheraddr(&sain->sain_myether);
- bzero((caddr_t)&sain->sain_myaddr, sizeof(struct in_addr));
- bzero((caddr_t)&sain->sain_hisaddr, sizeof(struct in_addr));
- sain->sain_hisether = etherbroadcastaddr;
- revarp(sip, sain, tmpbuf);
- }
-
-
- /*
- * Output an IP packet
- * Cause ARP to be invoked if necessary
- */
- ip_output(sip, buf, len, sain, tmpbuf)
- register struct saioreq *sip;
- caddr_t buf, tmpbuf;
- short len;
- register struct sainet *sain;
- {
- register struct ether_header *eh;
- register struct ip *ip;
-
- eh = (struct ether_header *)buf;
- ip = (struct ip *)(buf + sizeof(struct ether_header));
- if (bcmp((caddr_t)&ip->ip_dst,
- (caddr_t)&sain->sain_hisaddr,
- sizeof(struct in_addr)) != 0) {
- bcopy((caddr_t)&ip->ip_dst,
- (caddr_t)&sain->sain_hisaddr,
- sizeof (struct in_addr));
- arp(sip, sain, tmpbuf);
- }
- eh->ether_type = ETHERTYPE_IP;
- eh->ether_shost = sain->sain_myether;
- eh->ether_dhost = sain->sain_hisether;
- /* checksum the packet */
- ip->ip_sum = 0;
- ip->ip_sum = ipcksum((caddr_t)ip, sizeof (struct ip));
- if (len < ETHERMIN + sizeof(struct ether_header)) {
- len = ETHERMIN+sizeof(struct ether_header);
- }
- return (*sip->si_sif->sif_xmit)(sip->si_devdata, buf, len);
- }
-
- /*
- * Check incoming packets for IP packets
- * addressed to us. Also, respond to ARP packets
- * that wish to know about us.
- * Returns a length for any IP packet addressed to us, 0 otherwise.
- */
- ip_input(sip, buf, sain)
- register struct saioreq *sip;
- caddr_t buf;
- register struct sainet *sain;
- {
- register short len;
- register struct ether_header *eh;
- register struct ip *ip;
- register struct ether_arp *ea;
-
- len = (*sip->si_sif->sif_poll)(sip->si_devdata, buf);
- eh = (struct ether_header *)buf;
- if (eh->ether_type == ETHERTYPE_IP &&
- len >= sizeof(struct ether_header)+sizeof(struct ip)) {
- ip = (struct ip *)(buf + sizeof(struct ether_header));
- #ifdef NOREVARP
- if ((sain->sain_hisaddr.s_addr & 0xFF000000) == 0 &&
- bcmp((caddr_t)ðerbroadcastaddr,
- (caddr_t)&eh->ether_dhost,
- sizeof(struct ether_addr)) != 0 &&
- (in_broadaddr(sain->sain_hisaddr) ||
- in_lnaof(ip->ip_src) == in_lnaof(sain->sain_hisaddr))) {
- sain->sain_myaddr = ip->ip_dst;
- sain->sain_hisaddr = ip->ip_src;
- sain->sain_hisether = eh->ether_shost;
- }
- #endif
- if (bcmp((caddr_t)&ip->ip_dst,
- (caddr_t)&sain->sain_myaddr,
- sizeof(struct in_addr)) != 0)
- return (0);
- return (len);
- }
- if (eh->ether_type == ETHERTYPE_ARP &&
- len >= sizeof(struct ether_header) + sizeof(struct ether_arp)) {
- ea = (struct ether_arp *)(buf + sizeof(struct ether_header));
- if (ea->arp_pro != ETHERTYPE_IP)
- return (0);
- if (bcmp((caddr_t)ea->arp_spa,
- (caddr_t)&sain->sain_hisaddr,
- sizeof(struct in_addr)) == 0)
- sain->sain_hisether = ea->arp_sha;
- if (ea->arp_op == ARPOP_REQUEST &&
- (bcmp((caddr_t)ea->arp_tpa,
- (caddr_t)&sain->sain_myaddr,
- sizeof(struct in_addr)) == 0)) {
- ea->arp_op = ARPOP_REPLY;
- eh->ether_dhost = ea->arp_sha;
- eh->ether_shost = sain->sain_myether;
- ea->arp_tha = ea->arp_sha;
- bcopy((caddr_t)ea->arp_spa,
- (caddr_t)ea->arp_tpa,
- sizeof(ea->arp_tpa));
- ea->arp_sha = sain->sain_myether;
- bcopy((caddr_t)&sain->sain_myaddr,
- (caddr_t)ea->arp_spa,
- sizeof(ea->arp_spa));
- (*sip->si_sif->sif_xmit)(sip->si_devdata, buf,
- sizeof(struct arp_packet));
- }
- return (0);
- }
- return (0);
- }
-
- /*
- * arp
- * Broadcasts to determine Ethernet address given IP address
- * See RFC 826
- */
- arp(sip, sain, tmpbuf)
- register struct saioreq *sip;
- register struct sainet *sain;
- char *tmpbuf;
- {
- struct arp_packet out;
-
- if (in_broadaddr(sain->sain_hisaddr)
- #ifdef NOREVARP
- || (sain->sain_hisaddr.s_addr & 0xFF000000) == 0
- #endif
- ) {
- sain->sain_hisether = etherbroadcastaddr;
- return;
- }
- out.arp_eh.ether_type = ETHERTYPE_ARP;
- out.arp_ea.arp_op = ARPOP_REQUEST;
- out.arp_ea.arp_tha = etherbroadcastaddr; /* what we want */
- bcopy((caddr_t)&sain->sain_hisaddr,
- (caddr_t)out.arp_ea.arp_tpa,
- sizeof(sain->sain_hisaddr));
- comarp(sip, sain, &out, tmpbuf);
- }
-
- /*
- * Reverse ARP client side
- * Determine our Internet address given our Ethernet address
- * See RFC 903
- */
- revarp(sip, sain, tmpbuf)
- register struct saioreq *sip;
- register struct sainet *sain;
- char *tmpbuf;
- {
- struct arp_packet out;
-
- #ifdef NOREVARP
- bzero((caddr_t)&sain->sain_myaddr, sizeof(struct in_addr));
- bcopy((caddr_t)&sain->sain_myether.ether_addr_octet[3],
- (caddr_t)(&sain->sain_myaddr)+1, 3);
- #else
- out.arp_eh.ether_type = ETHERTYPE_REVARP;
- out.arp_ea.arp_op = REVARP_REQUEST;
- out.arp_ea.arp_tha = sain->sain_myether;
- /* What we want to find out... */
- bzero(out.arp_ea.arp_tpa, sizeof(struct in_addr));
- comarp(sip, sain, &out, tmpbuf);
- #endif
- }
-
- /*
- * Common ARP code
- * Broadcast the packet and wait for the right response.
- * Fills in *sain with the results
- */
- comarp(sip, sain, out, tmpbuf)
- register struct saioreq *sip;
- register struct sainet *sain;
- register struct arp_packet *out;
- char *tmpbuf;
- {
- register struct arp_packet *in = (struct arp_packet *)tmpbuf;
- register int e, count, time, feedback,len, delay = 2;
- char *ind = "-\|/";
- struct in_addr tmp_ia;
-
- out->arp_eh.ether_dhost = etherbroadcastaddr;
- out->arp_eh.ether_shost = sain->sain_myether;
- out->arp_ea.arp_hrd = ARPHRD_ETHER;
- out->arp_ea.arp_pro = ETHERTYPE_IP;
- out->arp_ea.arp_hln = sizeof(struct ether_addr);
- out->arp_ea.arp_pln = sizeof(struct in_addr);
- out->arp_ea.arp_sha = sain->sain_myether;
- bcopy((caddr_t)&sain->sain_myaddr,
- (caddr_t)out->arp_ea.arp_spa,
- sizeof(out->arp_ea.arp_spa));
- feedback = 0;
-
- for (count=0; ; count++) {
- if (count == WAITCNT) {
- if (out->arp_ea.arp_op == ARPOP_REQUEST) {
- printf("\nRequesting Ethernet address for ");
- bcopy((caddr_t)out->arp_ea.arp_tpa,
- (caddr_t)&tmp_ia, sizeof(tmp_ia));
- inet_print(tmp_ia);
- } else {
- printf("\nRequesting Internet address for ");
- ether_print(&out->arp_ea.arp_tha);
- }
- }
- e = (*sip->si_sif->sif_xmit)(sip->si_devdata, (caddr_t)out,
- sizeof *out);
- if (e)
- printf("X\b");
- else
- printf("%c\b", ind[feedback++ % 4]); /* Show activity */
-
- time = millitime() + (delay * 1000); /* broadcast delay */
- while (millitime() <= time) {
- len = (*sip->si_sif->sif_poll)(sip->si_devdata, tmpbuf);
- if (len < used_size)
- continue;
- if (in->arp_ea.arp_pro != ETHERTYPE_IP)
- continue;
- if (out->arp_ea.arp_op == ARPOP_REQUEST) {
- if (in->arp_eh.ether_type != ETHERTYPE_ARP)
- continue;
- if (in->arp_ea.arp_op != ARPOP_REPLY)
- continue;
- if (bcmp((caddr_t)in->arp_ea.arp_spa,
- (caddr_t)out->arp_ea.arp_tpa,
- sizeof(struct in_addr)) != 0)
- continue;
- if (count >= WAITCNT) {
- printf("Found at ");
- ether_print(&in->arp_ea.arp_sha);
- }
- sain->sain_hisether = in->arp_ea.arp_sha;
- return;
- } else { /* Reverse ARP */
- if (in->arp_eh.ether_type !=ETHERTYPE_REVARP)
- continue;
- if (in->arp_ea.arp_op != REVARP_REPLY)
- continue;
- if (bcmp((caddr_t)&in->arp_ea.arp_tha,
- (caddr_t)&out->arp_ea.arp_tha,
- sizeof (struct ether_addr)) != 0)
- continue;
-
- if (count >= WAITCNT) {
- printf("Internet address is ");
- bcopy((caddr_t)in->arp_ea.arp_tpa,
- (caddr_t)&tmp_ia, sizeof(tmp_ia));
- inet_print(tmp_ia);
- }
- bcopy((caddr_t)in->arp_ea.arp_tpa,
- (caddr_t)&sain->sain_myaddr,
- sizeof(sain->sain_myaddr));
- /*
- * short circuit first ARP
- */
- bcopy((caddr_t)in->arp_ea.arp_spa,
- (caddr_t)&sain->sain_hisaddr,
- sizeof(sain->sain_hisaddr));
- sain->sain_hisether = in->arp_ea.arp_sha;
- return;
- }
- }
-
- delay = delay * 2; /* Double the request delay */
- if (delay > 64) /* maximum delay is 64 seconds */
- delay = 64;
-
- (*sip->si_sif->sif_reset)(sip->si_devdata);
- }
- /* NOTREACHED */
- }
-
- /*
- * Return the host portion of an internet address.
- */
- in_lnaof(in)
- struct in_addr in;
- {
- register u_long i = ntohl(in.s_addr);
-
- if (IN_CLASSA(i))
- return ((i)&IN_CLASSA_HOST);
- else if (IN_CLASSB(i))
- return ((i)&IN_CLASSB_HOST);
- else
- return ((i)&IN_CLASSC_HOST);
- }
-
- /*
- * Test for broadcast IP address
- */
- in_broadaddr(in)
- struct in_addr in;
- {
- register u_long i = ntohl(in.s_addr);
-
- if (IN_CLASSA(i)) {
- i &= IN_CLASSA_HOST;
- return (i == 0 || i == 0xFFFFFF);
- } else if (IN_CLASSB(i)) {
- i &= IN_CLASSB_HOST;
- return (i == 0 || i == 0xFFFF);
- } else if (IN_CLASSC(i)) {
- i &= IN_CLASSC_HOST;
- return (i == 0 || i == 0xFF);
- } else
- return (0);
- /*NOTREACHED*/
- }
-
- /*
- * Compute one's complement checksum
- * for IP packet headers
- */
- ipcksum(cp, count)
- caddr_t cp;
- register unsigned short count;
- {
- register unsigned short *sp = (unsigned short *)cp;
- register unsigned long sum = 0;
- register unsigned long oneword = 0x00010000;
-
- count >>= 1;
- while (count--) {
- sum += *sp++;
- if (sum >= oneword) { /* Wrap carries into low bit */
- sum -= oneword;
- sum++;
- }
- }
- return (~sum);
- }
-
- inet_print(s)
- struct in_addr s;
- {
- printf("%d.%d.%d.%d\n",
- (s.s_addr >> 24) & 0xff,
- (s.s_addr >> 16) & 0xff,
- (s.s_addr >> 8) & 0xff,
- s.s_addr & 0xff);
- }
-
- ether_print(ea)
- struct ether_addr *ea;
- {
- register u_char *p = &ea->ether_addr_octet[0];
-
- printf("%x:%x:%x:%x:%x:%x\n", p[0], p[1], p[2], p[3], p[4], p[5]);
- }
-